﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PFI.ADCConv;
using PFI.DAConv;
using PFI.SCHVN;
using PFI.RegisterDevice;
using Utils.RamDevice;

namespace Algorithm.CalibrationWeights
{
    public class CalibratorOfWeights
    {
        ADC adcInst;
        public CalibratorOfWeights(ADC adcInst)
        {
            this.adcInst = adcInst;
        }
        public double GetAkalFirstDtrategy(int i)
        {
            return adcInst.dac.schvn.GetBitIdeal(i) * (1 + adcInst.dac.schvn.delta / 100);
        }
        public double GetAkalSecondDtrategy(int i)
        {
            adcInst.reg.SetPolinomNull();
            adcInst.reg.polinom[i]=1;
            double weightsOfI=adcInst.dac.ZnachenyaR(adcInst.reg);

            if(adcInst.reg as SCHVNRegister!=null)
            {
                ((SCHVNRegister)adcInst.reg).UCollapse(i);
                double weightsOfICollpased=adcInst.dac.ZnachenyaR(adcInst.reg);
                return weightsOfI>weightsOfICollpased ? weightsOfI: weightsOfICollpased;
            }
            else
            {
                throw new Exception("Not supported operation in GetAkalSecondDtrategy()");
            }
            
       }
        public void CalibrateWeights(StrategyEnums numOfStrategy)
        {
            switch (numOfStrategy)
            {
                case StrategyEnums.First:
                    CalibrateFirstStrategy();
                    break;
                case StrategyEnums.Second:
                    CalibrateSecondStrategy();
                    break;
                case StrategyEnums.Third:
                    CalibrateThirdStrategy();
                    break;
                default:
                    break;
            }
        }
        void CalibrateFirstStrategy()
        {
            RAM.Weights.InitRAMWeights(adcInst.dac.schvn);

            int kilToch = adcInst.dac.schvn.kilTochnux;

            for (int ik = kilToch; ik < adcInst.dac.schvn.n; ik++)
            {
                double q1 = adcInst.dac.ZnachenyaC(adcInst.SARAnalogSignal(GetAkalFirstDtrategy(ik)));
                double q2 = adcInst.dac.ZnachenyaC(adcInst.SARAnalogSignal(GetAkalFirstDtrategy(ik), ik));
                RAM.Weights.SetCalibrated(ik, q2 - q1);
            }
        }
        void CalibrateSecondStrategy()
        {
            RAM.Weights.InitRAMWeights(adcInst.dac.schvn);

            int kilToch = adcInst.dac.schvn.kilTochnux;

            for (int ik = kilToch; ik < adcInst.dac.schvn.n; ik++)
            {
                double q1 = adcInst.dac.ZnachenyaC(adcInst.SARAnalogSignal(GetAkalSecondDtrategy(ik)));
                double q2 = adcInst.dac.ZnachenyaC(adcInst.SARAnalogSignal(GetAkalSecondDtrategy(ik), ik));
                RAM.Weights.SetCalibrated(ik, q2 - q1);
            }
        }
        void CalibrateThirdStrategy()
        {
            RAM.Weights.InitRAMWeights(adcInst.dac.schvn);

            int kilToch = adcInst.dac.schvn.kilTochnux;

            for (int ik = kilToch; ik < adcInst.dac.schvn.n; ik++)
            {
                RAM.Weights.SetCalibrated(ik, CalibrateThirdStrategyLogic(ik));
            }
        }
        double CalibrateThirdStrategyLogic(int bitNum)
        {
            RAM.Weights.InitRAMWeights(adcInst.dac.schvn);

            int k=(int)(bitNum / 2);
            double res=0;

            SCHVNRegister adcReg = adcInst.reg as SCHVNRegister;
            if (adcReg != null)
            {
                adcReg.polinom[bitNum]=1;
                double aKalSuper = adcInst.dac.ZnachenyaR(adcReg);

                for (int i = 0; i < k; i++)
                {
                    double q1 = adcInst.dac.ZnachenyaC(adcInst.SARAnalogSignal(aKalSuper));
                    adcReg.UCollapse(bitNum-i);
                    double aKalCollapsed = adcInst.dac.ZnachenyaR(adcReg);

                    double q2 = adcInst.dac.ZnachenyaC(adcInst.SARAnalogSignal(aKalSuper>aKalCollapsed?aKalSuper:aKalCollapsed, bitNum));
                    res+=q1-q2;
                }
                return res/k;
            }
            else
                throw new Exception("Not supported operation in CalibrateThirdStrategyLogic()");
        }
    }
}
